package io.red;

import io.Archivo;
import io.Carpeta;
import io.Cliente;
import io.ItemAgenda;
import io.ItemBusqueda;
import io.Mensaje;
import io.hd.GestorArchivo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Mariano Zapata
 */
public class GestorRed {
    
    private Conexion conexion;
    private Buffer<Object> respuesta;
    private GestorRedListener listener;
    private GestorArchivo ga;
    
    public GestorRed()
    {
        conexion= null;
        respuesta= new Buffer<Object>();
        listener= null;
        ga= new GestorArchivo(this);
    }
    
    public void conectar(String ip, int puertoObjeto, int puertoArchivo) throws IOException
    {
        conexion= new Conexion(ip, puertoObjeto, puertoArchivo, this);
        conexion.start();
    }
    
    public boolean desconectarVerificando()
    {
        if (ga.hayArchivosAbiertos())
            return false;
        else
        {
            conexion.desconectar();
            return true;
        }
    }
    
    public void desconectarForzado(boolean guardarTodo) throws FileNotFoundException, IOException, InterruptedException
    {
        List<Archivo> archs= ga.obtenerArchivosAbiertos();
        for (Archivo a : archs)
            this.cerrarArchivo(a, guardarTodo);
        conexion.desconectar();
    }
    
    public void desconectarPorErrorGrave()
    {
        ga.destruirAplicacionesExternas();
        if (conexion != null)
            conexion.desconectar();
    }
    
    public void mensajeRecibido(Mensaje msj)
    {
        if (msj.obtenerTipo() < 0)
        {
            if (listener != null)
            {
                switch (msj.obtenerTipo())
                {
                    case -1:
                        listener.actualizarCarpeta((Carpeta) msj.obtenerCargaUtil());
                        break;
                    case -2:
                        Object [] o2= (Object []) msj.obtenerCargaUtil();
                        listener.quitarDeCarpeta((Carpeta) o2[0], o2[1]);
                        break;
                    case -3:
                        Object [] o3= (Object []) msj.obtenerCargaUtil();
                        listener.objetoCortado(o3[0], (Carpeta) o3[1], (Carpeta) o3[2]);
                        break;
                    case -4:
                        listener.actualizarListaAgenda((List<ItemAgenda>) msj.obtenerCargaUtil());
                        break;
                    case -5:
                        listener.quitarDeListaAgenda((ItemAgenda) msj.obtenerCargaUtil());
                        break;
                }
            }
        }
        else
            respuesta.escribir(msj.obtenerCargaUtil());
    }
    
    public void errorConexion(String info)
    {
        if (listener != null)
            listener.errorRed(info);
    }
    
    public void agregarGestorRedListener(GestorRedListener grl) {listener= grl;}
    
    public void quitarGestorRedListener() {listener= null;}
    
    public Carpeta expandirCarpeta(Carpeta aExpandir) throws InterruptedException
    {
        Mensaje msj= new Mensaje(0, aExpandir);
        conexion.enviarMensaje(msj);
        return (Carpeta) respuesta.leer();
    }
    
    public Cliente abrirCliente(Cliente aAbrir) throws InterruptedException, GestorRedException
    {
        Mensaje msj= new Mensaje(1, aAbrir);
        conexion.enviarMensaje(msj);
        Cliente resp= (Cliente) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede abrir el cliente " + aAbrir.getApellido() + ", " +
                    aAbrir.getNombres() + "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public boolean cerrarCliente(Cliente aCerrar) throws InterruptedException
    {
        Mensaje msj= new Mensaje(2, aCerrar);
        conexion.enviarMensaje(msj);
        return (Boolean) respuesta.leer();
    }
    
    public Object [] crearCliente(Cliente aCrear, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCrear;
        cu[1]= padre;
        Mensaje msj= new Mensaje(3, cu);
        conexion.enviarMensaje(msj);
        return (Object []) respuesta.leer();
    }
    
    public Carpeta guardarCliente(Cliente aGuardar) throws InterruptedException
    {
        Mensaje msj= new Mensaje(4, aGuardar);
        conexion.enviarMensaje(msj);
        return (Carpeta) respuesta.leer();
    }
    
    public boolean eliminarCliente(Cliente aEliminar, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aEliminar;
        cu[1]= padre;
        Mensaje msj= new Mensaje(5, cu);
        conexion.enviarMensaje(msj);
        return (Boolean) respuesta.leer();
    }
    
    public Carpeta cortarCliente(Cliente aCortar, Carpeta padreNuevo, Carpeta padreViejo)
            throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[3];
        cu[0]= aCortar;
        cu[1]= padreNuevo;
        cu[2]= padreViejo;
        Mensaje msj= new Mensaje(6, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede mover el cliente " + aCortar.getApellido() + ", " +
                    aCortar.getNombres() + "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public Carpeta copiarCliente(Cliente aCopiar, Carpeta padreNuevo) throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCopiar;
        cu[1]= padreNuevo;
        Mensaje msj= new Mensaje(7, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede copiar el cliente " + aCopiar.getApellido() + ", " +
                    aCopiar.getNombres() + "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public Carpeta crearCarpeta(Carpeta aCrear, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCrear;
        cu[1]= padre;
        Mensaje msj= new Mensaje(8, cu);
        conexion.enviarMensaje(msj);
        return (Carpeta) respuesta.leer();
    }
    
    public Carpeta guardarCarpeta(Carpeta aGuardar, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aGuardar;
        cu[1]= padre;
        Mensaje msj= new Mensaje(9, cu);
        conexion.enviarMensaje(msj);
        return (Carpeta) respuesta.leer();
    }
    
    public boolean eliminarCarpeta(Carpeta aEliminar, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aEliminar;
        cu[1]= padre;
        Mensaje msj= new Mensaje(10, cu);
        conexion.enviarMensaje(msj);
        return (Boolean) respuesta.leer();
    }
    
    public Carpeta cortarCarpeta(Carpeta aCortar, Carpeta padreNuevo, Carpeta padreViejo)
            throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[3];
        cu[0]= aCortar;
        cu[1]= padreNuevo;
        cu[2]= padreViejo;
        Mensaje msj= new Mensaje(11, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede mover la carpeta " + aCortar.getNombre() +
                    "\nporque su contenido está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public Carpeta copiarCarpeta(Carpeta aCopiar, Carpeta padreNuevo) throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCopiar;
        cu[1]= padreNuevo;
        Mensaje msj= new Mensaje(12, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede copiar la carpeta " + aCopiar.getNombre() +
                    "\nporque su contenido está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public Carpeta crearArchivo(File aCrear, Carpeta padre) throws FileNotFoundException, IOException, InterruptedException
    {
        Object [] cu= new Object[2];
        Archivo arch= new Archivo(new ArrayList<Long>());
        arch.setNombre(aCrear.getName());
        cu[0]= arch;
        cu[1]= padre;
        Mensaje msj= new Mensaje(13, cu);
        conexion.enviarMensaje(msj);
        ga.crearArchivoEnServidor(aCrear, conexion.obtenerSalidaArchivo());
        return (Carpeta) respuesta.leer();
    }
    
    public boolean abrirArchivo(Archivo aAbrir) throws InterruptedException, IOException
    {
        Mensaje msj= new Mensaje(14, aAbrir);
        conexion.enviarMensaje(msj);
        boolean resp= (Boolean) respuesta.leer();
        if (resp)
        {
            ga.abrirArchivo(aAbrir, conexion.obtenerEntradaArchivo());
            return true;
        }
        else
            return false;
    }
    
    public Carpeta cambiarNombreArchivo(Archivo aCambiar, Carpeta padre) throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCambiar;
        cu[1]= padre;
        Mensaje msj= new Mensaje(15, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede renombrar el documento " + aCambiar.getNombre() +
                    "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public void aplicacionExternaCerrada(Archivo archivo)
    {
        if (listener != null)
            listener.archivoCerrado(archivo);
    }
    
    public void errorAbrirAplicacion(Archivo archivo, String mensaje)
    {
        try {
            this.cerrarArchivo(archivo, false);
            if (listener != null)
                listener.errorAbrirAplicacion(mensaje);
        } catch (FileNotFoundException ex) {/*NUNCA SUCEDE PORQUE EL PARÁMETRO GUARDAR ES FALSO*/}
          catch (IOException ex) {/*NUNCA SUCEDE PORQUE EL PARÁMETRO GUARDAR ES FALSO*/}
          catch (InterruptedException ex) {/*NADA*/}
    }
    
    public boolean cerrarArchivo(Archivo aCerrar, boolean guardar)
            throws FileNotFoundException, IOException, InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCerrar;
        cu[1]= guardar;
        Mensaje msj= new Mensaje(16, cu);
        conexion.enviarMensaje(msj);
        ga.cerrarArchivo(aCerrar, guardar, conexion.obtenerSalidaArchivo());
        return (Boolean) respuesta.leer();
    }
    
    public boolean eliminarArchivo(Archivo aEliminar, Carpeta padre) throws InterruptedException
    {
        Object [] cu= new Object[2];
        cu[0]= aEliminar;
        cu[1]= padre;
        Mensaje msj= new Mensaje(17, cu);
        conexion.enviarMensaje(msj);
        boolean resp= (Boolean) respuesta.leer();
        if (resp)
        {
            ga.cerrarArchivoEliminado(aEliminar);
            return true;
        }
        else
            return false;
    }
    
    public Carpeta cortarArchivo(Archivo aCortar, Carpeta padreNuevo, Carpeta padreViejo)
            throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[3];
        cu[0]= aCortar;
        cu[1]= padreNuevo;
        cu[2]= padreViejo;
        Mensaje msj= new Mensaje(18, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede mover el documento " + aCortar.getNombre() +
                    "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public Carpeta copiarArchivo(Archivo aCopiar, Carpeta padreNuevo) throws InterruptedException, GestorRedException
    {
        Object [] cu= new Object[2];
        cu[0]= aCopiar;
        cu[1]= padreNuevo;
        Mensaje msj= new Mensaje(19, cu);
        conexion.enviarMensaje(msj);
        Carpeta resp= (Carpeta) respuesta.leer();
        if (resp == null)
            throw new GestorRedException("No se puede copiar el documento " + aCopiar.getNombre() +
                    "\nporque está siendo utilizado en otro lugar de la red.");
        else
            return resp;
    }
    
    public List<ItemAgenda> obtenerItemsAgenda(String fecha) throws InterruptedException
    {
        Mensaje msj= new Mensaje(20, fecha);
        conexion.enviarMensaje(msj);
        return (List<ItemAgenda>) respuesta.leer();
    }
    
    public List<ItemAgenda> crearItemAgenda(ItemAgenda aCrear) throws InterruptedException
    {
        Mensaje msj= new Mensaje(21, aCrear);
        conexion.enviarMensaje(msj);
        return (List<ItemAgenda>) respuesta.leer();
    }
    
    public boolean eliminarItemAgenda(ItemAgenda aEliminar) throws InterruptedException
    {
        Mensaje msj= new Mensaje(22, aEliminar);
        conexion.enviarMensaje(msj);
        return (Boolean) respuesta.leer();
    }
    
    public List<ItemAgenda> modificarItemAgenda(ItemAgenda aModificar) throws InterruptedException
    {
        Mensaje msj= new Mensaje(23, aModificar);
        conexion.enviarMensaje(msj);
        return (List<ItemAgenda>) respuesta.leer();
    }
    
    public List<ItemBusqueda> buscarCarpeta(String palabraClave) throws InterruptedException
    {
        Mensaje msj= new Mensaje(24, palabraClave);
        conexion.enviarMensaje(msj);
        return (List<ItemBusqueda>) respuesta.leer();
    }
    
    public List<ItemBusqueda> buscarArchivo(String palabraClave) throws InterruptedException
    {
        Mensaje msj= new Mensaje(25, palabraClave);
        conexion.enviarMensaje(msj);
        return (List<ItemBusqueda>) respuesta.leer();
    }
    
    public List<ItemBusqueda> buscarClienteApellido(String palabraClave) throws InterruptedException
    {
        Mensaje msj= new Mensaje(26, palabraClave);
        conexion.enviarMensaje(msj);
        return (List<ItemBusqueda>) respuesta.leer();
    }
    
    public List<ItemBusqueda> buscarClienteNombre(String palabraClave) throws InterruptedException
    {
        Mensaje msj= new Mensaje(27, palabraClave);
        conexion.enviarMensaje(msj);
        return (List<ItemBusqueda>) respuesta.leer();
    }
    
    public List<ItemBusqueda> buscarClienteDni(String palabraClave) throws InterruptedException
    {
        Mensaje msj= new Mensaje(28, palabraClave);
        conexion.enviarMensaje(msj);
        return (List<ItemBusqueda>) respuesta.leer();
    }
}
